RAC常见用法
- RACSignal
- RACSubject
- RACSequence
- RACMulticastConnection
- RACCommand
- RAC常用宏
- RAC-bind
- RAC-过滤
- RAC-映射
- RAC-组合
- RACSignal
一.核心
1.信号类
2.作用:只要有数据改变就会把数据包装成信号传递出去
3.只要有数据改变就会有信号发出
4.数据发出,并不是信号类发出,信号类不能发送数据
二.使用
1.创建信号
|
|
2.订阅信号(才能激活信号)
|
|
RACSignal底层实现 :
1、创建信号,首先把didSubscribe保存到信号中,还不会触发.
2、当信号被订阅,也就是调用signal的subscribrNext:nextBlock, subscribeNext内部会创建订阅者subscriber,并把nextBlock保存到subscriber中,subscribNext内部会调用signal的didSubscribe
3、signal的didsubcribe中调用【subscriber sendNext:@”发送数据”】,sendNext底层其实就是执行subscriber的nextBlock。
- RACSubject(热信号)
RACSubject继承于RACSignal遵守了RACSubscriber协议可以完全用RACSubject代替代理 /通知,与 RACSignal 以及 RACSequence 有着众多的类簇不同,RACSubject 在整个工程中并没有多少子类;不过,在大多数情况下,我们也只会使用 RACSubject 自己或者 RACReplaySubject,是一个可以『手动』控制的信号
相比于 RACSignal 丰富的头文件 ,RACSubject对外的接口并没有提供太多的方法:
|
|
唯一提供的接口就是用于返回一个新实例的 +subject 方法;除此之外,在笔者看来它与 RACSignal 最大的不同就是:RACSubject 实现了 RACSubscriber 协议,也就是下面的这些方法:
|
|
我们并不能在一个 RACSignal 对象上执行这些方法,只能在创建信号的 block 里面向遵循 RACSubscriber 协议的对象发送新的值或者错误,这也是 RACSubject 和父类最大的不同:在 RACSubject 实例初始化之后,也可以通过这个实例向所有的订阅者发送消息。
1.创建信号 跟RACSignal不一样,创建信号时没有block。
|
|
2.订阅信号(调用subscribeNext订阅信号,只是把订阅者保存起来,并且订阅者的nextBlock已经赋值了)
|
|
3.发送信号(调用subscribeNext订阅信号,只是把订阅者保存起来,并且订阅者的nextBlock已经赋值了)
|
|
注意 RACSubject 在 RACSignal 对象之上进行了简单的修改,将原有的冷信号改造成了热信号,将不可变变成了可变。
RACBehaviorSubject与RACReplaySubject
RACBehaviorSubject和RACReplaySubject是RACSubject的两个子类,前者在订阅时会向订阅者发送最新的消息,后者在订阅之后可以重新发送之前的所有消息序列。
先来介绍两者中实现较简单的RACBehaviorSubject,它在内部会保存一个currentValue 对象,也就是最后一次发送的消息:
|
|
在每次执行-sendNext:
时,都会对 RACBehaviorSubject
中保存的 currentValue
进行更新,并使用父类的 -sendNext:
方法,向所有的订阅者发送最新的消息:
|
|
RACBehaviorSubject
最重要的特性就是在订阅时,向最新的订阅者发送之前的消息,这是通过覆写-subscribe:
方法实现的。在调用子类的-subscribe:
方法之后,会在subscriber
对象上执行-sendNext:
方法:
|
|
RACReplaySubject相当于一个自带buffer 的RACBehaviorSubject,它可以在每次有新的订阅者订阅之后发送之前的全部消息。
|
|
RACSequence
高效的遍历数组和字典
|
|
RACMulticastConnection
当有多个订阅者,但是我们只想发送一个信号的时候怎么办?这时我们就可以用RACMulticastConnection,来实现。代码示例如下:
1.普通写法:
|
|
比较好的写法:
|
|
大概原理 :
- 1.创建connect,connect.sourceSignal -> RACSignal(原始信号) connect.signal -> RACSubject
- 2.订阅connect.signal,会调用RACSubject的subscribeNext,创建订阅者,而且把订阅者保存起来,不会执行block。
- 3.[connect connect]内部会订阅RACSignal(原始信号),并且订阅者是RACSubject
- 3.1.订阅原始信号,就会调用原始信号中的didSubscribe
- 3.2 didSubscribe,拿到订阅者调用sendNext,其实是调用RACSubject的sendNext
- 4.RACSubject的sendNext,会遍历RACSubject所有订阅者发送信号。
- 4.1 因为刚刚第二步,都是在订阅RACSubject,因此会拿到第二步所有的订阅者,调用他们的nextBlock
RACCommand
RACCommand:RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程,比如看事件有没有执行完毕
使用场景:监听按钮点击,网络请求
普通做法
123456789101112131415161718192021222324// RACCommand: 处理事件// 不能返回空的信号// 1.创建命令RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {//block调用,执行命令的时候就会调用NSLog(@"%@",input);// input 为执行命令传进来的参数// 这里的返回值不允许为nilreturn [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {[subscriber sendNext:@"执行命令产生的数据"];return nil;}];}];// 如何拿到执行命令中产生的数据呢?// 订阅命令内部的信号// ** 方式一:直接订阅执行命令返回的信号// 2.执行命令RACSignal *signal =[command execute:@2];// 这里其实用到的是replaySubject 可以先发送命令再订阅// 在这里就可以订阅信号了[signal subscribeNext:^(id x) {NSLog(@"%@",x);}];一般做法
12345678910111213141516171819202122// 1.创建命令RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {//block调用,执行命令的时候就会调用NSLog(@"%@",input); // input 为执行命令传进来的参数// 这里的返回值不允许为nilreturn [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {[subscriber sendNext:@"执行命令产生的数据"];return nil;}];}];// 订阅信号// 注意:这里必须是先订阅才能发送命令// executionSignals:信号源,信号中信号,signalofsignals:信号,发送数据就是信号[command.executionSignals subscribeNext:^(RACSignal *x) {[x subscribeNext:^(id x) {NSLog(@"%@", x);}];// NSLog(@"%@", x);}];// 2.执行命令[command execute:@2];高级做法
123456789101112131415161718// 1.创建命令RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {// block调用:执行命令的时候就会调用NSLog(@"%@", input);// 这里的返回值不允许为nilreturn [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {[subscriber sendNext:@"发送信号"];return nil;}];}];// 方式三// switchToLatest获取最新发送的信号,只能用于信号中信号。[command.executionSignals.switchToLatest subscribeNext:^(id x) {NSLog(@"%@", x);}];// 2.执行命令[command execute:@3];
|
|
|
|
RAC常用宏
RAC有许多强大而方便的宏。如下:
|
|
|
|
|
|
|
|
|
|
RAC-bind
|
|
- bind(绑定)的使用思想和Hook的一样—> 都是拦截API从而可以对数据进行操作,而影响返回数据。
- 发送信号的时候会来到30行的block。在这个block里我们可以对数据进行一些操作,那么35行打印的value和订阅绑定信号后的value就会变了。
RAC-过滤
有时候我们想要过滤一些信号,这时候我们便可以用RAC的过滤方法。过滤方法有好多种,如下代码,从不同情况下进行了分析。
123456789// 跳跃 : 如下,skip传入2 跳过前面两个值// 实际用处: 在实际开发中比如 后台返回的数据前面几个没用,我们想跳跃过去,便可以用skipRACSubject *subject = [RACSubject subject];[[subject skip:2] subscribeNext:^(id x) {NSLog(@"%@", x);}];[subject sendNext:@1];[subject sendNext:@2];[subject sendNext:@3];
|
|
|
|
|
|
|
|
|
|
|
|
RAC-映射
RAC的映射在实际开发中有什么用呢?比如我们想要拦截服务器返回的数据,给数据拼接特定的东西或想对数据进行操作从而更改返回值,类似于这样的情况下,我们便可以考虑用RAC的映射,实例代码如下
|
|
|
|
|
|
RAC-组合
把多个信号聚合成你想要的信号,(比如-当多个输入框都有值的时候按钮才可点击)
|
|
|
|
|
|
|
|
|
|